package com.feng.service.impl;

import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.feng.entity.Article;
import com.feng.entity.RestResponse;
import com.feng.entity.vo.*;
import com.feng.exception.SystemException;
import com.feng.mapper.ArticleMapper;
import com.feng.mapper.CategoryMapper;
import com.feng.entity.Category;
import com.feng.service.CategoryService;
import com.feng.utils.Const;
import com.feng.utils.HttpCodeEnum;
import com.feng.utils.WebUtils;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * (Category)表服务实现类
 *
 * @author feng
 * @since 2024-10-18 13:54:53
 */
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {

    final
    ArticleMapper articleMapper;

    public CategoryServiceImpl(ArticleMapper articleMapper) {
        this.articleMapper = articleMapper;
    }

    @Override
    public RestResponse listAllCategory() {
        LambdaQueryWrapper<Category> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Category::getStatus, Const.ZERO);
        List<Category> categoryList = list(wrapper);
        List<CategoryAllListVo> categoryAllListVoList = new ArrayList<>();
        categoryList.stream().parallel()
                .forEach(category -> {
                    categoryAllListVoList.add(new CategoryAllListVo(category.getId(), category.getName(), category.getDescription()));
                });
        return RestResponse.success(categoryAllListVoList);
    }

    @Override
    public RestResponse listAllCategoryPage(CategoryPageReqVo categoryPage) {
        LambdaQueryWrapper<Category> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StringUtils.hasText(categoryPage.getName()), Category::getName, categoryPage.getName())
                .eq(Objects.nonNull(categoryPage.getStatus()), Category::getStatus, categoryPage.getStatus());
        Page page = new Page<>(categoryPage.getCurrent(), categoryPage.getSize());
        page(page, wrapper);
        List<Category> categories = page.getRecords();
        List<CategoryPageRespVo> categoryPageResp = new ArrayList<>();
        categories.stream()
                .sorted(Comparator.comparing(Category::getId))
                .forEach(category -> {
                    categoryPageResp.add(new CategoryPageRespVo(category.getId(), category.getName(), category.getDescription(),
                            category.getStatus().toString(), category.getCreateTime()));
                });
        return RestResponse.success(new ArticleListPageVo(categoryPageResp, page.getTotal()));
    }

    @Override
    public RestResponse updateStatus(UpdateRoleStatusReqVo updateStatus) {
        Category category = new Category();
        BeanUtils.copyProperties(updateStatus, category);
        updateById(category);
        return RestResponse.success();
    }

    @Transactional
    @Override
    public RestResponse addCategory(CategoryAddVo categoryAdd) {
        if(tagNameExist(categoryAdd.getName())) throw new SystemException(HttpCodeEnum.CATEGORY_NAME_EXIST);
        getBaseMapper().AUTO_INCREMENT();
        Category category = new Category();
        BeanUtils.copyProperties(categoryAdd, category);
        save(category);
        return RestResponse.success();
    }

    @Override
    public RestResponse getCategoryById(Integer id) {
        Category category = getById(id);
        if (category == null) throw new SystemException(HttpCodeEnum.CATEGORY_NOT_EXIST);
        CategoryAddVo categoryAddVo = new CategoryAddVo(category.getId(), category.getName(), category.getDescription(),
                category.getStatus().toString());
        return RestResponse.success(categoryAddVo);
    }

    @Override
    public RestResponse updateCategory(CategoryAddVo categoryAdd) {
        Category category = new Category();
        category.setId(categoryAdd.getId()).setName(categoryAdd.getName()).setDescription(categoryAdd.getDescription())
                .setStatus(Integer.valueOf(categoryAdd.getStatus()));
        updateById(category);
        return RestResponse.success();
    }

    @Transactional
    @Override
    public RestResponse deleteCategory(Long id) {
        Category category = getById(id);
        if (category == null) throw new SystemException(HttpCodeEnum.CATEGORY_NOT_EXIST);
        LambdaQueryWrapper<Article> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Article::getCategoryId, id);
        List<Article> articleList = articleMapper.selectList(wrapper);
        if (articleList.size() > 0) {
            List<Article> articles = articleList.stream().map(article -> {
                article.setCategoryId(-1L);
                return article;
            }).collect(Collectors.toList());
            articleMapper.updateById(articles);
        }
        removeById(id);
        return RestResponse.success();
    }

    @Transactional
    @Override
    public RestResponse delBatchCategory(List<Long> ids) {
        removeByIds(ids);
        LambdaQueryWrapper<Article> wrapper = new LambdaQueryWrapper<>();
        List<List<Article>> listList = ids.stream().map(id -> {
            wrapper.eq(Article::getCategoryId, id);
            List<Article> articles = articleMapper.selectList(wrapper);
            wrapper.clear();
            return articles;
        }).toList();
        listList.stream()
                .forEach(articleList -> {
                    if (articleList.size() > 0) {
                        List<Article> articles = articleList.stream().map(article -> {
                            article.setCategoryId(-1L);
                            return article;
                        }).collect(Collectors.toList());
                        articleMapper.updateById(articles);
                    }
                });
        return RestResponse.success();
    }

    @Override
    public void export(HttpServletResponse response) {
        try (ServletOutputStream outputStream = response.getOutputStream()){
            WebUtils.excelResponseHeader(response, "分类");
            List<Category> categories = list();
            List<CategoryExportVo> exportVo = new ArrayList<>();
            categories.forEach(category -> exportVo.add(new CategoryExportVo(category.getId(),
                    category.getName(), category.getDescription(), category.getStatus(), category.getCreateTime())));
            EasyExcel.write(outputStream, CategoryExportVo.class)
                    .autoCloseStream(Boolean.FALSE).sheet("分类导出")
                    .doWrite(exportVo);
        } catch (Exception e) {
            response.reset();
            WebUtils.renderString(response, RestResponse.failure(500, "分类导出出现了错误").asJsonString());
        }
    }

    private boolean tagNameExist(String name) {
        LambdaQueryWrapper<Category> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Category::getName, name);
        long count = count(wrapper);
        return count > 0;
    }
}

